use std::ffi::c_void;
use serde::Serialize;
use winapi::um::psapi::{EnumProcesses, GetModuleBaseNameW, GetModuleFileNameExW};
use winapi::um::processthreadsapi::{OpenProcess};
use winapi::um::handleapi::CloseHandle;
use winapi::um::winnt::{PROCESS_QUERY_INFORMATION, PROCESS_VM_READ};
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::ptr;

#[derive(Serialize)]
pub struct ProcessInfo {
    pub pid: u32,
    pub name: String,
    pub exe_path: String,
}

pub fn scan_processes() -> Vec<ProcessInfo> {
    let mut processes_info: Vec<ProcessInfo> = Vec::new();

    unsafe {
        let mut processes: [u32; 1024] = [0; 1024];
        let mut bytes_needed = 0;
        let mut num_processes = 0;

        if EnumProcesses(processes.as_mut_ptr(), std::mem::size_of_val(&processes) as u32, &mut bytes_needed) != 0 {
            num_processes = bytes_needed / std::mem::size_of::<u32>() as u32;
        }

        for i in 0..num_processes {
            let pid = processes[i as usize];
            if pid == 0 {
                continue;
            }

            let process_handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, pid);
            if process_handle.is_null() {
                continue;
            }

            let process_name = get_process_name(process_handle).unwrap_or_else(|_| "未知".to_string());
            let exe_path = get_process_exe_path(process_handle).unwrap_or_else(|_| "未知路径".to_string());

            processes_info.push(ProcessInfo {
                pid,
                name: process_name,
                exe_path,
            });

            CloseHandle(process_handle);
        }
    }

    processes_info
}

fn get_process_name(process_handle: *mut c_void) -> Result<String, String> {
    let mut process_name: [u16; 512] = [0; 512];

    let len = unsafe {
        GetModuleBaseNameW(
            process_handle,
            ptr::null_mut(),
            process_name.as_mut_ptr(),
            process_name.len() as u32,
        )
    };

    if len > 0 {
        let os_string = OsString::from_wide(&process_name);
        Ok(os_string.to_string_lossy().trim_end_matches('\u{0}').to_string())
    } else {
        Err("无法获取进程名称".to_string())
    }
}

fn get_process_exe_path(process_handle: *mut c_void) -> Result<String, String> {
    let mut exe_path: [u16; 512] = [0; 512];

    let len = unsafe {
        GetModuleFileNameExW(
            process_handle,
            ptr::null_mut(),
            exe_path.as_mut_ptr(),
            exe_path.len() as u32,
        )
    };

    if len > 0 {
        let os_string = OsString::from_wide(&exe_path);
        Ok(os_string.to_string_lossy().trim_end_matches('\u{0}').to_string())
    } else {
        Err("无法获取进程路径".to_string())
    }
}
